package com.neusoft.hifly.commons.lang;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;

import org.apache.commons.lang3.StringUtils;

import com.neusoft.hifly.commons.lang.format.StrFormatter;
import com.neusoft.hifly.core.log.Log;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

/**
 * Title: 核心类库
 * <p>
 * Description: 处理字符串工具类
 * <p>
 * Copyright: 2019
 * <p>
 * Company: 东软汉枫
 *
 * @author lh_neu
 * @version 1.0.0
 */
public final class StringUtil extends StringUtils {
	/** 空字符串 */
	private static final String NULLSTR = "";

	/** 下划线 */
	private static final char SEPARATOR = '_';

	// Constants used by escapeHTMLTags
	private static final char[] QUOTE_ENCODE = "&quot;".toCharArray();
	private static final char[] AMP_ENCODE = "&amp;".toCharArray();
	private static final char[] LT_ENCODE = "&lt;".toCharArray();
	private static final char[] GT_ENCODE = "&gt;".toCharArray();

	/**
	 * 获取参数不为空值
	 *
	 * @param value
	 *            defaultValue 要判断的value
	 * @return value 返回值
	 */
	public static <T> T nvl(final T value, final T defaultValue) {
		return value != null ? value : defaultValue;
	}

	/**
	 * * 判断一个对象是否为空
	 *
	 * @param object
	 *            Object
	 * @return true：为空 false：非空
	 */
	public static boolean isNull(final Object object) {
		return object == null;
	}

	/**
	 * * 判断一个对象是否非空
	 *
	 * @param object
	 *            Object
	 * @return true：非空 false：空
	 */
	public static boolean isNotNull(final Object object) {
		return !StringUtil.isNull(object);
	}

	/**
	 * * 判断一个Collection是否为空， 包含List，Set，Queue
	 *
	 * @param coll
	 *            要判断的Collection
	 * @return true：为空 false：非空
	 */
	public static boolean isEmpty(final Collection<?> coll) {
		return StringUtil.isNull(coll) || coll.isEmpty();
	}

	/**
	 * * 判断一个Collection是否非空，包含List，Set，Queue
	 *
	 * @param coll
	 *            要判断的Collection
	 * @return true：非空 false：空
	 */
	public static boolean isNotEmpty(final Collection<?> coll) {
		return !StringUtil.isEmpty(coll);
	}

	/**
	 * * 判断一个对象数组是否为空
	 *
	 * @param objects
	 *            要判断的对象数组
	 ** @return true：为空 false：非空
	 */
	public static boolean isEmpty(final Object[] objects) {
		return StringUtil.isNull(objects) || (objects.length == 0);
	}

	/**
	 * * 判断一个对象数组是否非空
	 *
	 * @param objects
	 *            要判断的对象数组
	 * @return true：非空 false：空
	 */
	public static boolean isNotEmpty(final Object[] objects) {
		return !StringUtil.isEmpty(objects);
	}

	/**
	 * * 判断一个Map是否为空
	 *
	 * @param map
	 *            要判断的Map
	 * @return true：为空 false：非空
	 */
	public static boolean isEmpty(final Map<?, ?> map) {
		return StringUtil.isNull(map) || map.isEmpty();
	}

	/**
	 * * 判断一个Map是否为空
	 *
	 * @param map
	 *            要判断的Map
	 * @return true：非空 false：空
	 */
	public static boolean isNotEmpty(final Map<?, ?> map) {
		return !StringUtil.isEmpty(map);
	}

	/**
	 * * 判断一个字符串是否为空串
	 *
	 * @param str
	 *            String
	 * @return true：为空 false：非空
	 */
	public static boolean isEmpty(final String str) {
		return StringUtil.isNull(str) || StringUtil.NULLSTR.equals(str.trim());
	}

	/**
	 * * 判断一个字符串是否为非空串
	 *
	 * @param str
	 *            String
	 * @return true：非空串 false：空串
	 */
	public static boolean isNotEmpty(final String str) {
		return !StringUtils.isEmpty(str);
	}

	/**
	 * * 判断一个对象是否是数组类型（Java基本型别的数组）
	 *
	 * @param object
	 *            对象
	 * @return true：是数组 false：不是数组
	 */
	public static boolean isArray(final Object object) {
		return StringUtil.isNotNull(object) && object.getClass().isArray();
	}

	/**
	 * 去空格
	 */
	public static String trim(final String str) {
		return (str == null ? "" : str.trim());
	}

	/**
	 * 格式化文本, {} 表示占位符<br>
	 * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
	 * 如果想输出 {} 使用 \\转义 { 即可，如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
	 * 例：<br>
	 * 通常使用：format("this is {} for {}", "a", "b") -> this is a for b<br>
	 * 转义{}： format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
	 * 转义\： format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
	 *
	 * @param template
	 *            文本模板，被替换的部分用 {} 表示
	 * @param params
	 *            参数值
	 * @return 格式化后的文本
	 */
	public static String format(final String template, final Object... params) {
		if (StringUtil.isEmpty(params) || StringUtils.isEmpty(template)) {
			return template;
		}
		return StrFormatter.format(template, params);
	}

	/**
	 * 下划线转驼峰命名
	 */
	public static String toUnderScoreCase(final String str) {
		if (str == null) {
			return null;
		}
		final StringBuilder sb = new StringBuilder();
		// 前置字符是否大写
		boolean preCharIsUpperCase = true;
		// 当前字符是否大写
		boolean curreCharIsUpperCase = true;
		// 下一字符是否大写
		boolean nexteCharIsUpperCase = true;
		for (int i = 0; i < str.length(); i++) {
			final char c = str.charAt(i);
			if (i > 0) {
				preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
			} else {
				preCharIsUpperCase = false;
			}

			curreCharIsUpperCase = Character.isUpperCase(c);

			if (i < (str.length() - 1)) {
				nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
			}

			if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
				sb.append(StringUtil.SEPARATOR);
			} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
				sb.append(StringUtil.SEPARATOR);
			}
			sb.append(Character.toLowerCase(c));
		}

		return sb.toString();
	}

	/**
	 * 是否包含字符串
	 *
	 * @param str
	 *            验证字符串
	 * @param strs
	 *            字符串组
	 * @return 包含返回true
	 */
	public static boolean inStringIgnoreCase(final String str, final String... strs) {
		if (str != null && strs != null) {
			for (final String s : strs) {
				if (str.equalsIgnoreCase(StringUtils.trim(s))) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。 例如：HELLO_WORLD->HelloWorld
	 *
	 * @param name
	 *            转换前的下划线大写方式命名的字符串
	 * @return 转换后的驼峰式命名的字符串
	 */
	public static String convertToCamelCase(final String name) {
		final StringBuilder result = new StringBuilder();
		// 快速检查
		if (name == null || name.isEmpty()) {
			// 没必要转换
			return "";
		} else if (!name.contains("_")) {
			// 不含下划线，仅将首字母大写
			return name.substring(0, 1).toUpperCase() + name.substring(1);
		}
		// 用下划线将原始字符串分割
		final String[] camels = name.split("_");
		for (final String camel : camels) {
			// 跳过原始字符串中开头、结尾的下换线或双重下划线
			if (camel.isEmpty()) {
				continue;
			}
			// 首字母大写
			result.append(camel.substring(0, 1).toUpperCase());
			result.append(camel.substring(1).toLowerCase());
		}
		return result.toString();
	}

	/**
	 * TODO 【终极技巧】JAVA中获取当前运行的类名、方法名以及行数
	 *
	 * @author lh_neu
	 * @date 2011-9-15 下午04:04:20
	 * @return 类名、方法名以及行数
	 */
	public static String getTraceInfo() {
		final StackTraceElement[] stacks = new Throwable().getStackTrace();
		final StackTraceElement c = stacks[1];
		final StringBuffer sb = new StringBuffer(c.getFileName());
		sb.append(":").append(c.getLineNumber()).append("(" + c.getMethodName() + ")");
		//		final StringBuffer sb = new StringBuffer("class: ");
		//		sb.append(c.getClassName()).append("; method: ").append(c.getMethodName()).append("; number: ")
		//		.append(c.getLineNumber());
		return sb.toString();
	}

	/**
	 * 字符串转码
	 *
	 * @param str
	 *            字符串
	 * @return 转码
	 */
	@SuppressWarnings("deprecation")
	public static String encode(final String str) {
		if (StringUtils.isEmpty(str)) {
			return str;
		}
		return URLEncoder.encode(str);
	}

	/**
	 * 字符串转码
	 *
	 * @param str
	 *            字符串
	 * @param recvEncoding
	 *            编码
	 * @return 转码
	 */
	@SuppressWarnings("deprecation")
	public static String encode(final String str, final String recvEncoding) {
		if (StringUtils.isEmpty(str)) {
			return str;
		}
		try {
			return URLEncoder.encode(str, recvEncoding);
		} catch (final UnsupportedEncodingException e) {
			return URLEncoder.encode(str);
		}
	}

	/**
	 * 字符串转码
	 *
	 * @param str
	 *            字符串
	 * @return 转码
	 */
	@SuppressWarnings("deprecation")
	public static String decode(final String str) {
		if (StringUtils.isEmpty(str)) {
			return str;
		}
		return URLDecoder.decode(str);
	}

	/**
	 * 字符串转码
	 *
	 * @param str
	 *            字符串
	 * @param recvEncoding
	 *            编码
	 * @return 转码
	 */
	@SuppressWarnings("deprecation")
	public static String decode(final String str, final String recvEncoding) {
		if (StringUtils.isEmpty(str)) {
			return str;
		}
		try {
			return URLDecoder.decode(str, recvEncoding);
		} catch (final UnsupportedEncodingException e) {
			return URLDecoder.decode(str);
		}
	}

	/**
	 * 将数组转换为字符串
	 *
	 * @param arr
	 *            待转换的数组
	 * @return 转换后的字符串
	 */
	public static String arr2Str(Object[] arr) {
		if (arr == null) {
			arr = new String[0];
		}
		return StringUtils.join(arr, StringConstants.STRING_SPLIT_FLAG_3);
	}

	/**
	 * 将字符串转换为字符串数组
	 *
	 * @param str
	 *            待转换的字符串 以","分割
	 * @return 转换后的字符串数组
	 */
	public static String[] str2Arr(final String str) {
		return StringUtil.str2Arr(str, StringConstants.STRING_SPLIT_FLAG_3);
	}

	/**
	 * 将字符串转换为字符串数组
	 *
	 * @param str
	 *            待转换的字符串
	 * @param split
	 *            分割符号
	 * @return 转换后的字符串数组
	 */
	public static String[] str2Arr(String str, final String split) {
		if (StringUtils.isEmpty(str)) {
			str = "";
		}
		final StringTokenizer token = new StringTokenizer(str, split);
		final String[] dayArray = new String[token.countTokens()];
		int i = 0;
		String temp = null;
		while (token.hasMoreTokens()) {
			temp = token.nextToken();
			if (StringUtils.isEmpty(temp) || "null".equalsIgnoreCase(temp)) {
				continue;
			}
			dayArray[i++] = temp;
		}
		return dayArray;
	}

	/**
	 * 将字符串转换为字符串数组
	 *
	 * @param str
	 *            待转换的字符串 以","分割
	 * @return 转换后的字符串数组
	 */
	public static List<String> str2List(final String str) {
		return StringUtil.str2List(str, StringConstants.STRING_SPLIT_FLAG_3);
	}

	/**
	 * 将字符串转换为字符串数组
	 *
	 * @param str
	 *            待转换的字符串
	 * @param split
	 *            分割符号
	 * @return 转换后的字符串数组
	 */
	public static List<String> str2List(String str, final String split) {
		if (StringUtils.isEmpty(str)) {
			str = "";
		}
		final StringTokenizer token = new StringTokenizer(str, split);
		final List<String> dayArray = new ArrayList<String>(token.countTokens());
		String temp = null;
		while (token.hasMoreTokens()) {
			temp = token.nextToken();
			if (StringUtils.isEmpty(temp) || "null".equalsIgnoreCase(temp)) {
				continue;
			}
			dayArray.add(temp);
		}
		return dayArray;
	}

	/**
	 * 将URL中的中文使用URLEncoder转码
	 *
	 * @param url
	 *            待转换的url
	 * @param character
	 *            字符集
	 * @return 转换后的url
	 */
	public static String urlEncode(final String url, final String character) {
		String temp = null;
		final StringBuffer sb = new StringBuffer("");
		if (StringUtils.isNotEmpty(url)) {
			for (int i = 0; i < url.length(); i++) {
				temp = url.substring(i, i + 1);
				if (temp.matches("[\\u4e00-\\u9fa5]+")) {
					try {
						sb.append(URLEncoder.encode(temp, character));
					} catch (final UnsupportedEncodingException e) {
						Log.error(e.getMessage());
					}
				} else {
					sb.append(temp);
				}
				temp = null;
			}
		}
		return sb.toString();
	}

	/**
	 * 是否包含汉字
	 *
	 * @param str
	 *            字符串
	 * @return true/false
	 */
	public static boolean isIncludeChinese(final String str) {
		if (StringUtils.isNotEmpty(str)) {
			String temp = null;
			for (int i = 0; i < str.length(); i++) {
				temp = str.substring(i, i + 1);
				if (temp.matches("[\\u4e00-\\u9fa5]+")) {
					return true;
				}
				temp = null;
			}
		}
		return false;
	}

	/**
	 * 根据总长度在字符串前补齐位置的0
	 *
	 * @author lh_neu
	 * @param code
	 *            字符串
	 * @param length
	 *            总长度
	 * @param isSub
	 *            字符串长度 < 总长度 时，是否截取
	 * @return 补齐后的编码
	 */
	public static final String getZero(final String code, final int length, final boolean isSub) {
		if (StringUtils.isEmpty(code)) {
			return "";
		}
		final int len = length - code.length();
		if (len <= 0) {
			// 根据总长度截取前部分
			if (isSub) {
				return StringUtils.substring(code, 0, length);
			} else {
				return code;
			}
		}
		final StringBuffer sb = new StringBuffer();
		for (int i = 0; i < len; i++) {
			sb.append("0");
		}
		return sb.toString() + code;
	}

	private static final char[] zeroArray = "0000000000000000000000000000000000000000000000000000000000000000"
			.toCharArray();

	/**
	 * 填充0到指定长度的字符串前端，并返回一个新的结果字符串。
	 * <p>
	 * 例如，如果初始的字符串是“9999”和所需的长度为8，结果将“00009999”。
	 * <p>
	 * 这种类型的填充是用于创建需要的数值为字符数据的存储和排序。
	 * <p>
	 * 注意：目前此方法实施允许的最大<tt>length</tt> of 64.
	 *
	 * @param string
	 *            the original String to pad.
	 * @param length
	 *            the desired length of the new padded String.
	 * @return a new String padded with the required number of 0's.
	 */
	public static String zeroPadString(final String string, final int length) {
		if ((string == null) || (string.length() > length)) {
			return string;
		}
		final StringBuilder buf = new StringBuilder(length);
		buf.append(StringUtil.zeroArray, 0, length - string.length()).append(string);
		return buf.toString();
	}

	/**
	 * 填充0到指定长度的字符串后侧，并返回一个新的结果字符串。
	 * <p>
	 * 例如，如果初始的字符串是“9999”和所需的长度为8，结果将“99990000”。
	 * <p>
	 * 这种类型的填充是用于创建需要的数值为字符数据的存储和排序。
	 * <p>
	 * 注意：目前此方法实施允许的最大<tt>length</tt> of 64.
	 *
	 * @param string
	 *            the original String to pad.
	 * @param length
	 *            the desired length of the new padded String.
	 * @return a new String padded with the required number of 0's.
	 */
	public static String zeroPadAfterString(final String string, final int length) {
		if ((string == null) || (string.length() > length)) {
			return string;
		}
		final StringBuilder buf = new StringBuilder(length);
		buf.append(string).append(StringUtil.zeroArray, 0, length - string.length());
		return buf.toString();
	}

	/**
	 * String转换InputStream
	 *
	 * @param str
	 *            String
	 * @return InputStream
	 */
	public static InputStream string2InputStream(final String str) {
		if (StringUtils.isNotEmpty(str)) {
			final ByteArrayInputStream stream = new ByteArrayInputStream(str.getBytes());
			return stream;
		} else {
			return null;
		}
	}

	/**
	 * InputStream转换String
	 *
	 * @author lh_neu
	 * @date 2010-6-22 下午05:33:54
	 * @param in
	 *            InputStream
	 * @return String
	 */
	public static String inputStream2String(InputStream in) {
		if (in != null) {
			final StringBuffer buffer = new StringBuffer();
			final byte[] buf = new byte[512];
			int len;
			try {
				while ((len = in.read(buf)) != -1) {
					buffer.append(new String(buf, 0, len));
				}
				return buffer.toString();
			} catch (final IOException e) {
				Log.error(e.getMessage());
			} finally {
				try {
					in.close();
					in = null;
				} catch (final IOException e) {
					Log.error(e.getMessage());
				}
			}
		}
		return null;
	}

	/**
	 * 获取字符串内的所有汉字的汉语拼音并大写每个字的首字母
	 *
	 * @author lh_neu
	 * @date 2010-6-30 下午12:40:53
	 * @param chinese
	 *            汉字
	 * @param split
	 *            每个拼音间的分隔符，默认为空串
	 * @return 拼音
	 */
	public static String str2Pinyin(final String chinese, String split) {
		if (StringUtils.isEmpty(chinese)) {
			return null;
		}
		if (StringUtils.isEmpty(split)) {
			split = "";
		}
		final HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
		format.setCaseType(HanyuPinyinCaseType.LOWERCASE); // 小写
		format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); // 不标声调
		format.setVCharType(HanyuPinyinVCharType.WITH_V); // u:的声母替换为v
		try {
			final StringBuilder sb = new StringBuilder();
			for (int i = 0; i < chinese.length(); i++) {
				if (String.valueOf(chinese.charAt(i)).matches("[\\u4e00-\\u9fa5]+")) {

					// 中文的再转换
					final String[] array = PinyinHelper.toHanyuPinyinStringArray(chinese.charAt(i), format);
					if ((array == null) || (array.length == 0)) {
						continue;
					}

					/* 处理特殊的姓氏 */
					if (i == 0) {
						if ("都".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Du" + split);
						} else if ("区".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Ou" + split);
						} else if ("黑".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("He" + split);
						} else if ("盖".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Ge" + split);
						} else if ("查".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Zha" + split);
						} else if ("曾".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Zeng" + split);
						} else if ("缪".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Miao" + split);
						} else if ("晟".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Cheng" + split);
						} else if ("单".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Shan" + split);
						} else if ("乐".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Yue" + split);
						} else if ("员".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Yun" + split);
						} else if ("仇".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Qiu" + split);
						} else if ("尉".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Yu" + split);
						} else if ("万".equals(String.valueOf(chinese.charAt(i)))) {
							sb.append("Mo" + split);
						} else {
							final String s = array[0]; // 不管多音字,只取第一个
							final char c = s.charAt(0); // 大写第一个字母
							final String pinyin = String.valueOf(c).toUpperCase().concat(s.substring(1));
							sb.append(pinyin + split);
						}
					} else {
						final String s = array[0]; // 不管多音字,只取第一个
						final char c = s.charAt(0); // 大写第一个字母
						final String pinyin = String.valueOf(c).toUpperCase().concat(s.substring(1));
						sb.append(pinyin + split);
					}

				} else {
					// 非中文，直接拼接
					sb.append(chinese.charAt(i));
				}

			}
			return StringUtils.substringBeforeLast(sb.toString(), split);
		} catch (final BadHanyuPinyinOutputFormatCombination e) {
			Log.error(e.getMessage());
		}
		return null;
	}

	/**
	 * 去掉list中重复数据
	 * <p>
	 * 利用HashSet实现了秒级去重
	 *
	 * @return 去掉了多少个节点
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static int removeListDuplicate(final List<?> list) {
		if (list == null || list.isEmpty()) {
			return 0;
		}
		final int old = list.size();
		final Set set = new HashSet(list);
		list.clear();
		list.addAll(set);
		return old - list.size();
	}

	/**
	 * This method takes a string which may contain HTML tags (ie, &lt;b&gt;, &lt;table&gt;, etc) and converts the
	 * '&lt'' and '&gt;' characters to their HTML escape sequences. It will also replace LF with &lt;br&gt;.
	 *
	 * @param in
	 *            the text to be converted.
	 * @return the input string with the characters '&lt;' and '&gt;' replaced with their HTML escape sequences.
	 */
	public static String escapeHTMLTags(final String in) {
		if (in == null) {
			return null;
		}
		char ch;
		int i = 0;
		int last = 0;
		final char[] input = in.toCharArray();
		final int len = input.length;
		final StringBuilder out = new StringBuilder((int) (len * 1.3));
		for (; i < len; i++) {
			ch = input[i];
			if (ch > '>') {
			} else if (ch == '<') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(StringUtil.LT_ENCODE);
			} else if (ch == '>') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(StringUtil.GT_ENCODE);
			} else if (ch == '\n') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append("<br>");
			}
		}
		if (last == 0) {
			return in;
		}
		if (i > last) {
			out.append(input, last, i - last);
		}
		return out.toString();
	}

	/**
	 * 返回中文的拼音首字母
	 *
	 * @author lh_neu
	 * @date Mar 21, 2011 4:28:23 PM
	 * @param str
	 *            汉字
	 * @return 拼音的首字母
	 */
	public static String str2PinyinHeadChar(final String str) {
		final StringBuffer convert = new StringBuffer("");
		if (StringUtils.isNotEmpty(str)) {
			for (int j = 0; j < str.length(); j++) {
				final char word = str.charAt(j);
				final String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
				if (pinyinArray != null) {
					convert.append(pinyinArray[0].charAt(0));
				} else {
					convert.append(word);
				}
			}
		}
		return StringUtils.upperCase(convert.toString());
	}

	/**
	 * 转义字符串中所有必要的字符，所以它可以在一个XML文档中使用。
	 *
	 * @param string
	 *            the string to escape.
	 * @return the string with appropriate characters escaped.
	 */
	public static String escapeForXML(final String string) {
		if (string == null) {
			return null;
		}
		char ch;
		int i = 0;
		int last = 0;
		final char[] input = string.toCharArray();
		final int len = input.length;
		final StringBuilder out = new StringBuilder((int) (len * 1.3));
		for (; i < len; i++) {
			ch = input[i];
			if (ch > '>') {
			} else if (ch == '<') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(StringUtil.LT_ENCODE);
			} else if (ch == '&') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(StringUtil.AMP_ENCODE);
			} else if (ch == '"') {
				if (i > last) {
					out.append(input, last, i - last);
				}
				last = i + 1;
				out.append(StringUtil.QUOTE_ENCODE);
			}
		}
		if (last == 0) {
			return string;
		}
		if (i > last) {
			out.append(input, last, i - last);
		}
		return out.toString();
	}

	/**
	 * XML转义序列转换成普通字符字符串。
	 *
	 * @param string
	 *            the string to unescape.
	 * @return the string with appropriate characters unescaped.
	 */
	public static String unescapeFromXML(String string) {
		if (StringUtils.isEmpty(string)) {
			return string;
		}
		string = StringUtil.replaceXml(string, "&lt;", "<");
		string = StringUtil.replaceXml(string, "&gt;", ">");
		string = StringUtil.replaceXml(string, "&quot;", "\"");
		string = StringUtil.replaceXml(string, "&#39;", "'");
		return StringUtil.replaceXml(string, "&amp;", "&");
	}

	/**
	 * 将HTML中的符号转义
	 * <p>
	 * 使用htmlEscape进行字符转换
	 *
	 * @param map
	 *            需要转换的MAP
	 */
	public static void encodingHtml(final Map<String, String> map) {
		if (map != null) {
			final Iterator<Entry<String, String>> iter = map.entrySet().iterator();
			while (iter.hasNext()) {
				final Map.Entry<String, String> entry = iter.next();
				final String key = entry.getKey();
				String value = entry.getValue();
				if (StringUtils.isNotEmpty(value)) {
					value = StringUtil.encodingHtml(value);
					map.put(key, value);
				}
			}
		}
	}

	/**
	 * 将转义后的HTML符号还原为原有形态
	 * <p>
	 * 使用htmlUnescape进行字符转换
	 *
	 * @param map
	 *            需要转换的MAP
	 */
	public static void decodingHtml(final Map<String, String> map) {
		if (map != null) {
			final Iterator<Entry<String, String>> iter = map.entrySet().iterator();
			while (iter.hasNext()) {
				final Map.Entry<String, String> entry = iter.next();
				final String key = entry.getKey();
				String value = entry.getValue();
				if (StringUtils.isNotEmpty(value)) {
					value = StringUtil.decodingHtml(value);
					map.put(key, value);
				}
			}
		}
	}

	/**
	 * 将HTML中的符号转义
	 *
	 * @param source
	 *            原字符串
	 * @return 转义后字符串
	 */
	public static String encodingHtml(String source) {
		if (StringUtils.isEmpty(source)) {
			return source;
		}
		source = StringUtils.replace(source, "&", "&amp;");
		source = StringUtils.replace(source, "<", "&lt;");
		source = StringUtils.replace(source, ">", "&gt;");
		//		source = replace(source, " ", "&nbsp;");
		source = StringUtils.replace(source, "\"", "&#0034;");
		source = StringUtils.replace(source, "\'", "&#0039;");
		return source;
	}

	/**
	 * 将转义后的HTML符号还原为原有形态
	 *
	 * @param source
	 *            原字符串
	 * @return 转义后字符串
	 */
	public static String decodingHtml(String source) {
		if (StringUtils.isEmpty(source)) {
			return source;
		}
		source = StringUtils.replace(source, "&amp;", "&");
		source = StringUtils.replace(source, "&lt;", "<");
		source = StringUtils.replace(source, "&gt;", ">");
		source = StringUtils.replace(source, "&nbsp;", " ");
		source = StringUtils.replace(source, "&#0034;", "\"");
		source = StringUtils.replace(source, "&#0039;", "\'");
		return source;
	}

	/**
	 * 替换xml特殊字符
	 *
	 * @author lh_neu
	 * @date 2013-12-13 下午12:57:22
	 * @param str
	 *            原字符
	 * @return 替换后的字符
	 */
	public static String chopWhitespace(final String str) {
		if (StringUtils.isBlank(str)) {
			return "";
		}
		final StringBuilder sb = new StringBuilder("");
		for (int i = 0; i < str.length(); i++) {
			final char ch = str.charAt(i);
			final int ci = ch;
			if (9 == ci || 10 == ci || 13 == ci || 32 <= ci && !Character.isISOControl(ci)) {
				sb.append(ch);
			}
		}
		return sb.toString();
	}

	/**
	 * 为字符串添加省略号
	 *
	 * <pre>
	 *      user1@jivesoftware.com/home
	 * </pre>
	 *
	 * and a maximum length of 20 characters, the abbreviate method will return:
	 *
	 * <pre>
	 *      user1@jivesoftware.c...
	 * </pre>
	 *
	 * @param str
	 *            the String to abbreviate.
	 * @param maxWidth
	 *            the maximum size of the string, minus the ellipsis.
	 * @return the abbreviated String, or <tt>null</tt> if the string was <tt>null</tt>.
	 */
	public static String abbreviate(final String str, final int maxWidth) {
		if (null == str) {
			return null;
		}

		if (str.length() <= maxWidth) {
			return str;
		}

		return str.substring(0, maxWidth) + "...";
	}

	/**
	 * 删除字符可能使跨站点脚本攻击提供输入字符串。
	 *
	 * <pre>
	 * &lt; &gt; &quot; ' % ; ) ( &amp; + -
	 * </pre>
	 *
	 * @param string
	 *            input
	 * @return Input without certain characters;
	 */
	public static String removeXSSCharacters(String input) {
		final String[] xss = { "<", ">", "\"", "'", "%", ";", ")", "(", "&", "+", "-" };
		for (final String xs : xss) {
			input = input.replace(xs, "");
		}
		return input;
	}

	/**
	 * Replaces all instances of oldString with newString in string.
	 *
	 * @param string
	 *            the String to search to perform replacements on.
	 * @param oldString
	 *            the String that should be replaced by newString.
	 * @param newString
	 *            the String that will replace all instances of oldString.
	 * @return a String will all instances of oldString replaced by newString.
	 */
	private static String replaceXml(final String string, final String oldString, final String newString) {
		if (string == null) {
			return null;
		}
		int i = 0;
		// Make sure that oldString appears at least once before doing any processing.
		if ((i = string.indexOf(oldString, i)) >= 0) {
			// Use char []'s, as they are more efficient to deal with.
			final char[] string2 = string.toCharArray();
			final char[] newString2 = newString.toCharArray();
			final int oLength = oldString.length();
			final StringBuilder buf = new StringBuilder(string2.length);
			buf.append(string2, 0, i).append(newString2);
			i += oLength;
			int j = i;
			// Replace all remaining instances of oldString with newString.
			while ((i = string.indexOf(oldString, i)) > 0) {
				buf.append(string2, j, i - j).append(newString2);
				i += oLength;
				j = i;
			}
			buf.append(string2, j, string2.length - j);
			return buf.toString();
		}
		return string;
	}

	/**
	 * 替换begin到end之间的内容（包括begin和end）
	 *
	 * @param string
	 *            原串
	 * @param begin
	 *            开始符
	 * @param end
	 *            接收符
	 * @param ignoreCase
	 *            是否忽略大小写
	 * @param replaceStr
	 *            待替换的字符
	 * @return 处理后的字符串
	 */
	public static String replace(String string, String begin, String end, final boolean ignoreCase,
			final String replaceStr) {
		if (StringUtils.isEmpty(string) || StringUtils.isEmpty(begin) || StringUtils.isEmpty(end)) {
			return string;
		}
		if (ignoreCase) {
			if (string.toLowerCase().indexOf(begin.toLowerCase()) <= -1
					|| string.toLowerCase().indexOf(end.toLowerCase()) <= -1) {
				return string;
			}
		} else {
			if (string.indexOf(begin) <= -1 || string.indexOf(end) <= -1) {
				return string;
			}
		}
		// 去掉换行
		string = string.replaceAll("\r\t", " ");

		if (ignoreCase) {
			//大小写不敏感
			begin = begin.toLowerCase();
			end = end.toLowerCase();
			string = string.replaceAll("(?i)" + begin, begin);
			string = string.replaceAll("(?i)" + end, end);
		}
		final String beginStr = StringUtils.substringBefore(string, begin);
		final String endStr = StringUtils.substringAfter(string, end);
		if (StringUtils.isNotEmpty(replaceStr)) {
			return beginStr + replaceStr + endStr;
		} else {
			return beginStr + endStr;
		}
	}

	/**
	 * 生成随即数
	 *
	 * @param pwdLen
	 *            生成的密码的总长度
	 * @return 密码的字符串
	 */
	public static String genRandomNum(final int pwdLen) {
		return StringUtil.genRandomNum(pwdLen, false);
	}

	/**
	 * 生成随即数
	 *
	 * @param pwdLen
	 *            生成的密码的总长度
	 * @param isNumber
	 *            是否存数字
	 * @return 密码的字符串
	 */
	public static String genRandomNum(final int pwdLen, final boolean isNumber) {
		// 35是因为数组是从0开始的，26个字母+10个数字
		int maxNum = 36;
		int i; // 生成的随机数
		int count = 0; // 生成的密码的长度
		char[] str;
		if (isNumber) {
			maxNum = 10;
			str = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
		} else {
			str = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
					'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
		}
		final StringBuffer pwd = new StringBuffer("");
		final Random r = new Random();
		while (count < pwdLen) {
			// 生成随机数，取绝对值，防止生成负数，

			i = Math.abs(r.nextInt(maxNum)); // 生成的数最大为36-1

			if (i >= 0 && i < str.length) {
				if (!isNumber) {
					// 首位不能是数字
					if (count == 0 && i > 25) {
						continue;
					}
				}

				pwd.append(str[i]);
				count++;
			}
		}

		return pwd.toString();
	}

	/**
	 * 忽略大小写的substringBefore
	 *
	 * @param str
	 *            原串
	 * @param searchChar
	 *            比较字符
	 * @return 截取的字符串
	 */
	public static String substringBeforeIgnoreCase(final String str, final String separator) {
		final int i = StringUtils.indexOfIgnoreCase(str, separator);
		if (i >= 0) {
			return StringUtils.substring(str, 0, i);
		}
		return str;
	}

	/**
	 * 忽略大小写的substringAfter
	 *
	 * @param str
	 *            原串
	 * @param searchChar
	 *            比较字符
	 * @return 截取的字符串
	 */
	public static String substringAfterIgnoreCase(final String str, final String separator) {
		final int i = StringUtils.indexOfIgnoreCase(str, separator);
		if (i >= 0) {
			return StringUtils.substring(str, i + separator.length());
		}
		return "";
	}

	/**
	 * 统计字符串str1中包含几个str2
	 *
	 * @param str1
	 *            原串
	 * @param str2
	 *            比较字符
	 * @return 重复个数
	 */
	public static int countIndexOf(final String str1, final String str2) {
		if (StringUtils.isEmpty(str1) || StringUtils.isEmpty(str2)) {
			return 0;
		}
		final int len1 = str1.length();//获取原来的字符串长度
		final String s1 = str1.replaceAll(str2, "");
		final int len2 = s1.length();
		return len1 - len2;//出现的次数
	}

	/**
	 * 替换\r\n，windows、linux下均支持
	 *
	 * @param str
	 *            字符串
	 * @return 替换后的字符串
	 */
	public static String replaceEnter(final String str) {
		if (StringUtils.isEmpty(str)) {
			return null;
		}
		return str.replaceAll(StringConstants.TAG_R, "").replaceAll(StringConstants.TAG_N, "");
	}

	/**
	 * 计算对象占用的字节数
	 *
	 * @author lh_neu
	 * @param o
	 *            对象
	 * @return 自己数
	 */
	public static int size(final Object o) {
		if (o == null) {
			return 0;
		}
		ByteArrayOutputStream buf = null;
		ObjectOutputStream out = null;
		try {
			buf = new ByteArrayOutputStream(64);
			out = new ObjectOutputStream(buf);
			out.writeObject(o);
			out.flush();
			return buf.size();
		} catch (final IOException e) {
			return 0;
		} finally {
			try {
				if (buf != null) {
					buf.close();
				}
				if (out != null) {
					out.close();
				}
			} catch (final Exception e) {
			}
		}
	}

	/**
	 * 将字符串转成unicode
	 *
	 * @param str
	 *            待转字符串
	 * @return unicode字符串
	 */
	public static String convertToUnicode(String str) {
		if (StringUtils.isEmpty(str)) {
			return str;
		}
		str = (str == null ? "" : str);
		String tmp;
		final StringBuffer sb = new StringBuffer(1000);
		char c;
		int i, j;
		sb.setLength(0);
		for (i = 0; i < str.length(); i++) {
			c = str.charAt(i);
			sb.append("\\u");
			j = (c >>> 8); // 取出高8位
			tmp = Integer.toHexString(j);

			if (tmp.length() == 1) {
				sb.append("0");
			}

			sb.append(tmp);
			j = (c & 0xFF); // 取出低8位
			tmp = Integer.toHexString(j);
			if (tmp.length() == 1) {
				sb.append("0");
			}
			sb.append(tmp);
		}
		return (new String(sb));
	}

	/**
	 * unicode解码（unicode编码转中文）
	 *
	 * @param str
	 *            字符串
	 * @return String
	 */
	public static String unicodeDecode(final String str) {
		if (StringUtils.isEmpty(str)) {
			return str;
		}
		char aChar;
		final int len = str.length();
		final StringBuffer outBuffer = new StringBuffer(len);
		for (int x = 0; x < len;) {
			aChar = str.charAt(x++);
			if (aChar == '\\') {
				aChar = str.charAt(x++);

				if (aChar == 'u') {
					// Read the xxxx
					int value = 0;
					for (int i = 0; i < 4; i++) {
						aChar = str.charAt(x++);
						switch (aChar) {
							case '0':
							case '1':
							case '2':
							case '3':
							case '4':
							case '5':
							case '6':
							case '7':
							case '8':
							case '9':
								value = (value << 4) + aChar - '0';
								break;
							case 'a':
							case 'b':
							case 'c':
							case 'd':
							case 'e':
							case 'f':
								value = (value << 4) + 10 + aChar - 'a';
								break;
							case 'A':
							case 'B':
							case 'C':
							case 'D':
							case 'E':
							case 'F':
								value = (value << 4) + 10 + aChar - 'A';
								break;
							default:
								throw new IllegalArgumentException("Malformed   \\uxxxx   encoding.");
						}
					}
					outBuffer.append((char) value);
				} else {
					if (aChar == 't') {
						aChar = '\t';
					} else if (aChar == 'r') {
						aChar = '\r';
					} else if (aChar == 'n') {
						aChar = '\n';
					} else if (aChar == 'f') {
						aChar = '\f';
					}
					outBuffer.append(aChar);
				}
			} else {
				outBuffer.append(aChar);
			}
		}
		return outBuffer.toString();
	}

	/**
	 * 替换字符串
	 *
	 * @param sb
	 *            StringBuffer
	 * @param oldStr
	 *            原
	 * @param newStr
	 *            新
	 * @return 字符串
	 */
	public static StringBuffer replaceAll(final StringBuffer sb, final String oldStr, final String newStr) {
		if (sb == null || oldStr == null || newStr == null) {
			return sb;
		}
		int i = sb.indexOf(oldStr);
		final int oldLen = oldStr.length();
		final int newLen = newStr.length();
		while (i > -1) {
			sb.delete(i, i + oldLen);
			sb.insert(i, newStr);
			i = sb.indexOf(oldStr, i + newLen);
		}
		return sb;
	}

	/**
	 * 测试
	 *
	 * @author lh_neu
	 * @date Mar 16, 2011 1:16:14 PM
	 * @param args
	 *            参数
	 */
	public static void main(final String[] args) {
		System.out.println("字符串翻转：" + StringUtils.reverse("1234"));

		System.out.println(StringUtils.capitalize("abc_def"));
		//		System.out.println(StringUtil.genRandomNum(6));
		//		System.out.println(StringUtil.unicodeDecode("%u7BA1%u7406%u5458"));
		//		System.out.println(StringUtil.urlEncode("测试", "UTF-8"));
		//		StringBuffer sb = new StringBuffer("AND model.base.userNickname LIKE '%昵称%'");
		//		System.out.println(replaceAll(sb, "model.base.", "base."));
		//
		//		System.out.println(zeroPadString("1012", 6));
		//		System.out.println(zeroPadAfterString("1012", 6));
		//
		//		String imgStr = "fjoBGi\r\n9CJIHa";
		//		System.out.println(replaceEnter(imgStr));
		//
		//		System.out.println(unescapeFromXML("&lt;c:out value=&quot;${COMPACT_votherfee}&quot;/&gt;"));
		//		System.out.println(isIncludeChinese("1231松岛枫23"));

		//		String oldFilePath = "jkgl\\V1.0.0_Base/cyList.jsp";
		//		oldFilePath = oldFilePath.replaceAll("\\\\", "_");
		//		System.out.println(oldFilePath);
		//		oldFilePath = oldFilePath.replaceAll("\\/", "_");
		//		System.out.println(oldFilePath);

		//		System.out.println(HtmlUtils.htmlEscape(";"));
		//		//		System.out.println(StringUtil.getTraceInfo());
		//		//		final String name = "asdf123lihui";
		//		//		System.out.println(StringUtil.str2Pinyin(name, ""));
		//		//		System.out.println(StringUtil.str2PinyinHeadChar(name));
		//		System.out.println(StringUtil.replace("123123DDaD123beginAAAfsdfsdfend斯蒂芬斯蒂芬斯蒂芬", "BEGIN", "end", false, "_"));
		//		final String t = "aaaaaaaaaa<table></table>aaa<table></table>";
		//		final String s = "<TABLE";
		//
		//		System.out.println("length=" + t.length());
		//		System.out.println(t.indexOf(s, 0));
		//		System.out.println(StringUtil.ignoreIndexOf(t, s, 0));
		//		System.out.println(t.lastIndexOf(s));
		//		System.out.println(StringUtil.ignoreLastIndexOf(t, s));
	}
}
